package com.xhlj.security;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xhlj.entity.UserInfo;
import com.xhlj.mapper.UserInfoMapper;
import com.xhlj.utils.JwtHelper;
import com.xhlj.utils.PayLoad;
import com.xhlj.utils.RedisKey;
import com.xhlj.utils.Result;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    /*
     * OncePerRequestFilter只会验证一次,在之前验证过了的话我们就不验证了
     * */
    @Autowired
    private JwtHelper helper;
    //    private JwtHelper helper=new JwtHelper();
    @Resource
    private UserInfoMapper mapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            String upgrade = request.getHeader("upgrade") == null ? "" : request.getHeader("upgrade");
            if (upgrade.equals("websocket")) {
                dealWithWebsocket(request);
            } else {
                // 服了在那个map里，调试的时候一直size是0,结果就是他
                if (request.getServletPath().equals("/notify")) {
                    dealWithAlipay(request);
                } else if (request.getServletPath().equals("/mj/receive")) {
                    RequestWrapper requestWrapper=new RequestWrapper(request);
                    dealWithGenerateImage(requestWrapper);
                    chain.doFilter(requestWrapper, response);
                    return;
                }
                else if(!StringUtils.isEmpty(request.getHeader("Token"))) {
                    dealWithHaveToken(request, response);

                }else {


                }


            }
            chain.doFilter(request, response);

        } catch (Exception exception) {
            System.out.println("jwt验证失败:" + request.getParameterMap() + "\n");
            System.out.println("jwt验证失败:" + exception.getMessage() + "\n");
            System.out.println("jwt验证失败:" + exception.getStackTrace() + "\n");
        }
    }

    /*
     * 本方法主要解决论坛的socket问题
     * */
    private void dealWithWebsocket(HttpServletRequest request) throws Exception {
        try {
            String username = request.getParameter("username");
            setAuthentication(username);
        } catch (Exception exception) {
            System.out.println(String.format("dealWithWebsocket error:%S", exception.getMessage()));
            throw new Exception(String.format("dealWithWebsocket error:%S", exception.getMessage()));
        }
    }

    /*
     * 根据用户名设置身份信息
     * */
    void setAuthentication(String username) throws Exception {
        try {
            LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserInfo::getUserPhone, username);
            UserInfo userInfo = mapper.selectOne(wrapper);
            List<GrantedAuthority> authorityList = new ArrayList<>();
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userInfo.getUserPhone(), userInfo.getUserPassword(), authorityList);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (Exception exception) {
            System.out.println(String.format("setAuthentication error:%S\n username:%s", exception.getMessage(), username));
            throw new Exception(String.format("setAuthentication error:%S\n username:%s", exception.getMessage(), username));
        }
    }

    void dealWithGenerateImage(HttpServletRequest request) throws Exception {
        String username = null;

        try {
            //TODO:从通知中读取出task_id
            ServletInputStream inputStream = request.getInputStream();;
            // 将整个流读入字节数组
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int nRead;
            byte[] data = new byte[1024];
            while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }
            buffer.flush();
            byte[] byteArray = buffer.toByteArray();
            // 将字节数组转换为字符串，同时处理潜在的编码问题

            String content = new String(byteArray, Charset.forName("UTF-8")); // 首先尝试 UTF-8

            // 将字节数组（假设是 JSON 数据）包装成 ByteBuffer
            // 使用 Jackson 将 ByteBuffer 转换为 JSON 字符串
            ObjectMapper mapper = new ObjectMapper();
            Map<String, String> map = mapper.readValue(content, HashMap.class);
            String taskId = map.get("task_id");

            String img_url = map.get("image_url");
//            System.out.println("generated img_url = " + img_url);
            username = stringRedisTemplate.opsForValue().get(RedisKey.GenerateImg_prefix + taskId);
//            System.out.println("手机号："+username);
            setAuthentication(username);

        } catch (Exception exception) {
            System.out.println(String.format("dealWithGenerateImage error:%S\n username:%s", exception.getMessage(), username));
            throw new Exception(String.format("dealWithGenerateImage error:%S\n username:%s", exception.getMessage(), username));
        }
    }

    void dealWithAlipay(HttpServletRequest request) throws Exception {

        String username = null;
        try {
            /*处理支付宝的通知*/
            String outTradeNo = request.getParameter("out_trade_no");
            System.out.println(outTradeNo);
            username = stringRedisTemplate.opsForValue().get(RedisKey.Alipay_prefex + outTradeNo);
            setAuthentication(username);
        } catch (Exception exception) {
            System.out.println(String.format("dealWithAlipay error:%S\n username:%s", exception.getMessage(), username));
            throw new Exception(String.format("dealWithAlipay error:%S\n username:%s", exception.getMessage(), username));

        }
    }

    /*
     * 处理各种有token的情况
     * */
    void dealWithHaveToken(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String username = null;
        try {
            String token = request.getHeader("Token");
//            String token = "eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAA_6tWKi5NUrJSiox099ANDXYNUtJRSq0oULIyNDc0NDE1NjMw0FEqSKzMyU9MASqrjlEqyMjPS_UrzU1KLYpRcohRMrQ0NbS0MAAqNohR0olRKi1OLfJMAUoZGkJ5IZUFqWCl_n4-nn6uMUq1SrUA0vjv6XgAAAA.g30jxYVAHpO0PA4bDi-fKFz0xOVaOlTn8plKbbyOm8cTTe3SUb4sXcKcWVf5KhfYKATdsEEghy3KGNgr4V_ChQ";
            ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
            PayLoad payLoad = helper.getPayLoad(token);
            String key = JSON.toJSONString(payLoad).replaceAll(":", "@");
            String redisToken = ops.get(RedisKey.Login_token_prefix + key);
            System.out.println(key);
            /*验证token是否过期*/
            if (StringUtils.isEmpty(token)) {
                /*放行,让他走接下来的过滤器*/
            } else if (redisToken == null) {
//            if(redisToken==null)  反正放到redis里
                response.getWriter().print(JSON.toJSONString(Result.build(null, 400, "token timeout")));
                return;
            } else {
//           刷新Token的时间
                LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(UserInfo::getUserId, payLoad.getUserId());
                UserInfo userInfo = mapper.selectOne(wrapper);
                List<GrantedAuthority> authorityList = new ArrayList<>();
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userInfo.getUserPhone(), userInfo.getUserPassword(), authorityList);
                SecurityContextHolder.getContext().setAuthentication(authentication);

            }
        } catch (Exception exception) {
            System.out.println(String.format("dealWithToken error:%S\n username:%s", exception.getMessage(), username));
            throw new Exception(String.format("dealWithToken error:%S\n username:%s", exception.getMessage(), username));
        }
    }
}
